﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using T.FAS.Runtime.Base.Entity;
using T.FAS.Runtime.Metadata.Entity.DataModel;
using T.FAS.Runtime.Metadata.Entity;

namespace T.FAS.Runtime.DataModel.Dao
{
    /// <summary>
    /// 元数据验证接口
    /// </summary>
    public class DataQueryValidator : IMetaDataDesignValidator, IMetaDataRuntimeValidator
    {
        public string MetaDataType = DataModelConst.DQMetaType;
        public string MetaDataTypeCN = DataModelConst.DQMetaName;
        //DO依赖DB校验
        private readonly DatabaseValidator _databaseValidator = new DatabaseValidator();
        private readonly DatabaseLogic _databaseLogic = new DatabaseLogic();
        private readonly DataQueryLogic _dataQueryLogic = new DataQueryLogic();
        private readonly DataObjectLogic _dataObjectLogic = new DataObjectLogic();

        public bool CreateMetadata(IMetaDataContent metaDataContent)
        {
            var Assert = GetEntityValidateResult(metaDataContent);
            Assert.FailIfErrorResult();
            return Assert.GetAssertResult().Result;
        }

        public bool DeleteMetadata(IMetaDataContent metaDataContent)
        {
            FASAssert Assert = new FASAssert();
            Assert.IsNotNull(metaDataContent.MetaDataID, $"数据库删除时未指定MetaDataID");
            Assert.FailIfErrorResult();
            return Assert.GetAssertResult().Result;
        }

        public bool GetMetadata(IMetaDataContent metaDataContent)
        {
            var Assert = GetEntityValidateResult(metaDataContent, CRUDType.Retrive);
            Assert.FailIfErrorResult();
            return Assert.GetAssertResult().Result;
        }

        public bool UpdateMetadata(IMetaDataContent metaDataContent)
        {
            //因为目前更新采用先删后加的方式，所以采用相同校验规则
            return CreateMetadata(metaDataContent);
        }

        public bool GetMetadataRTP(IMetaDataContent metaDataContent)
        {
            //目前运行时获取元数据跟设计时一致
            return GetMetadata(metaDataContent);
        }

        /// <summary>
        /// 元数据修复
        /// </summary>
        /// <param name="metaDataContent"></param>
        public void Repair(IMetaDataContent metaDataContent)
        {
            object meta = metaDataContent;
            FASAssert fASAssert = new FASAssert();
            #region 注册校验信息
            //注册修复的校验方法
            fASAssert.Validator += delegate (ref object ValidateObj, object[] paramList)
            {
                return GetEntityValidateResult(ValidateObj as IMetaDataContent, CRUDType.Retrive, fASAssert)?.Result;
            };
            //注册回调
            fASAssert.FinishValidate += delegate (ref object ValidateObj)
            {
                _dataQueryLogic.Update(metaDataContent as DataQuery);
            };
            //注册修复方法
            //DQ数据源找不到DO，处理方法：删掉Source&Column&Sort等
            fASAssert.RegistErrorHandler(DataModelValidateCodeConst.DQ.DeleteInvalidSource,
                (frame) =>
                {
                    try
                    {
                        var dq = frame.ValidateContext.ValidateObj as DataQuery;
                        dynamic otherParams = frame.ValidateContext.OtherParams;
                        List<string> deleteSoureIDs = otherParams.CurrentSources;
                        var invalidSources = dq.DataQuerySources.Where(s => deleteSoureIDs.Contains(s.ID));
                        foreach (var source in invalidSources)
                        {
                            //删除列
                            var dropColIDs = dq.DataQueryColumns.Where(col => col.DataQuerySourceID == source.ID)?.Select(col => col.ID).ToList();
                            if (dropColIDs != null && dropColIDs.Count > 0)
                                dq.DataQueryColumns.RemoveAll(col => col.DataQuerySourceID == source.ID);
                            //删除排序
                            dq.DataQuerySorts.RemoveAll(sort => sort.DataObjectID == source.DataObjectID);
                            //删除关联
                            dq.DataQueryJoins.RemoveAll(join => join.LeftSourceID == source.ID || join.RightSourceID == source.ID);
                            //Filter条件如何删除
                            dq.DataQuerySources.RemoveAll(s => s.ID == source.ID);
                            //处理子查询，删掉引用了被删除的Source列的子查询
                            dq.SubQuerys.RemoveAll(sub => dropColIDs.Contains(sub.MainQueryColumnID));
                        }
                        return ErrorRepairResult.SuccessAndRetry;
                    }
                    catch (Exception e)
                    {
                        return ErrorRepairResult.Error;
                    }
                });
            #endregion
            //执行校验
            fASAssert.Validate(ref meta, 0, null);
        }

        private FASAssert GetEntityValidateResult(IMetaDataContent metaDataContent, CRUDType crudType = CRUDType.Create, FASAssert fASAssert = null)
        {
            FASAssert Assert;
            if (fASAssert != null)
                Assert = fASAssert;
            else
                Assert = new FASAssert();

            DataQuery Meta = metaDataContent as DataQuery;
            Assert.IsNotNull(Meta, $"请检查IMetaDataContent参数");
            Assert.FailIfErrorResult(); //如果为空引用直接抛出异常
            if (!string.IsNullOrWhiteSpace(metaDataContent?.MetaData?.MetaTypeID))
                MetaDataType = metaDataContent?.MetaData?.MetaTypeID;
            var unifyCode = $"元数据类型{MetaDataType}的元数据Code:{Meta.MetaDataCode},ID:{Meta.MetaDataID}";

            /***********通用系统字段校验**********/
            StringBuilder errmsg = new StringBuilder();
            //MetaDataID,MetaDataCode,MetaDataName等字段校验

            //暂时不做系统字段校验
            //var systemFieldsCheckResult = EntityCheckTools.CheckSystemFields(Meta);
            //Assert.IsTrue(systemFieldsCheckResult.Result, systemFieldsCheckResult.ErrorMsg);

            if (crudType == CRUDType.Create)
            {
                var MetaDataInfo = metaDataContent.MetaData;
                Assert.IsNotNull(MetaDataInfo, $"{unifyCode}的系统字段:{nameof(metaDataContent.MetaData)}不能为空!");
                //租户ID验证
                Assert.IsNotNull(MetaDataInfo.TenantId, $"{unifyCode}的系统字段:{nameof(MetaDataInfo.TenantId)}不能为空!");
            }

            //DQ校验

            /*********************DataQuerySource校验***********************/
            Assert.IsTrue(Meta.DataQuerySources != null && Meta.DataQuerySources.Count > 0, $"{unifyCode}的数据源集合不能为空！", true);
            foreach (var source in Meta.DataQuerySources)
            {
                if (crudType == CRUDType.Create)
                {
                    source.DataObject = _dataObjectLogic.GetDataObjectByID(source.DataObjectID);
                }
            }
            var invalidSources = Meta.DataQuerySources.Where(source => source.DataObject == null)?.Select(source => source.ID)?.ToList();
            //无效的数据源校验
            AssertErrorFrame assertErrorFrame = Assert.CreateFrame(DataModelValidateCodeConst.DQ.DeleteInvalidSource);
            assertErrorFrame.ValidateContext.OtherParams = new
            {
                CurrentSources = invalidSources
            };

            Assert.IsTrue(invalidSources == null || invalidSources.Count == 0,
                        $"{DataModelErrorCode.GetNeedRepairErrorCode(DataModelConst.DQMetaType)}," +
                        $"{unifyCode}的数据源:{string.Join(",", invalidSources)}对应的DataObject在数据库中找不到对应的实例", true, assertErrorFrame);

            /*********************DataQueryColumns校验***********************/
            Assert.IsTrue(Meta.DataQueryColumns != null && Meta.DataQueryColumns.Count > 0, $"{unifyCode}的数据源集合不能为空！", true);
            foreach (var column in Meta.DataQueryColumns)
            { 

            }

            /*********************DataQueryJoins校验***********************/
            if (Meta.DataQuerySources.Count > 1)    //当数据源数量大于1时，需要Join条件连接
            {
                Assert.IsTrue(Meta.DataQueryJoins != null && Meta.DataQueryJoins.Count > 0, $"{unifyCode}的数据源集合数量为:{Meta.DataQuerySources.Count}，必须指定Join关联条件！");
            }

            /*********************DataQueryFilters校验***********************/
            if (Meta.DataQueryFilters != null && Meta.DataQueryFilters.Count > 0)
            {

            }

            /*********************DataQuerySorts校验***********************/
            if (Meta.DataQuerySorts != null && Meta.DataQuerySorts.Count > 0)
            {

            }

            /*********************DataQueryParams校验***********************/
            if (Meta.DataQueryParams != null && Meta.DataQueryParams.Count > 0)
            {

            }

            /*********************SubQuerys校验***********************/
            if (Meta.SubQuerys != null && Meta.SubQuerys.Count > 0)
            {
                //如果使用子查询，主查询内不能包含分组&聚合列
                var column = Meta.DataQueryColumns.Where(col => col.ColumnType == ColumnType.Group || col.ColumnType == ColumnType.Aggregate).ToList();
                Assert.IsTrue(column.Count == 0, $"{unifyCode}启用子查询时，Column列集合中不能包含分组或聚合列", true);

                foreach (var sub in Meta.SubQuerys)
                {
                    if (crudType == CRUDType.Retrive)
                    {
                        if (sub.SubQuery != null) 
                        {
                            var subQueryRelatedColumn = sub.SubQuery.DataQueryColumns?.FirstOrDefault(col => col.ID == sub.SubQueryColumnID);
                            Assert.IsTrue(subQueryRelatedColumn != null, $"{unifyCode}启用子查询，子查询:{sub.SubQuery.Code}的列集合中不包含关联列:{sub.SubQueryColumnID}", true);
                        }
                    }
                }
            }

            /**********获取时加入的额外控制***********/
            if (crudType == CRUDType.Retrive)
            {
                Assert.IsNotNull(Meta.ID, $"{unifyCode}的系统字段:{nameof(Meta.ID)}不能为空!");
                Assert.IsNotNull(Meta.Name, $"{unifyCode}的系统字段:{nameof(Meta.Name)}不能为空!");
                Assert.IsNotNull(Meta.Code, $"{unifyCode}的系统字段:{nameof(Meta.Code)}不能为空!");

                foreach (var column in Meta.DataQueryColumns.Where(col => col.ColumnType == ColumnType.Normal))
                {
                    if (column.DataColumn == null)
                        throw new FasException(DataModelErrorCode.DQ.InitError,
                            $"{DataModelErrorCode.GetNeedRepairErrorCode(DataModelConst.DQMetaType)},{unifyCode}的列:{column.ID},{column.Alias}对应的DO:{column.DataObject?.Code}的列:{column.DataObjectColumnID}不存在!");
                }
            }

            return Assert;
        }
    }
}
